<?php
/**
 * Created by Benjamin.
 * Date: 2020/5/7
 * Time: 10:40
 */

namespace App\WebSocket;


use App\Logic\AppLogic;
use App\Services\HelpService;
use App\Services\MasterService;
use EasySwoole\Component\TableManager;
use EasySwoole\EasySwoole\Config;


class WebSocketEvent
{


    /**自定义消息处理
     * @param $request
     * @param $response
     * @param $table
     */
    public function onMessage(\swoole_http_request $request, \swoole_http_response $response, $table){

    }


    /**自定义消息处理
     * @param $request
     * @param $response
     * @param $table
     */
    public function onConnect(\swoole_http_request $request, \swoole_http_response $response, $table){
        // new 调用者对象

    }

    /**
     * 握手事件
     *
     * @param \swoole_http_request  $request
     * @param \swoole_http_response $response
     * @return bool
     */
    public function onHandShake(\swoole_http_request $request, \swoole_http_response $response)
    {
        /** 此处自定义握手规则 返回 false 时中止握手 */
        if (!$this->customHandShake($request, $response)) {
            $response->end();
            return false;
        }

        /** 此处是  RFC规范中的WebSocket握手验证过程 必须执行 否则无法正确握手 */
        if ($this->secWebsocketAccept($request, $response)) {
            $response->end();
            return true;
        }

        $response->end();
        return false;
    }

    /**
     * 自定义握手事件
     *
     * @param \swoole_http_request  $request
     * @param \swoole_http_response $response
     * @return bool
     */
    protected function customHandShake(\swoole_http_request $request, \swoole_http_response $response): bool
    {
        /**
         * 这里可以通过 http request 获取到相应的数据
         * 进行自定义验证后即可
         * (注) 浏览器中 JavaScript 并不支持自定义握手请求头 只能选择别的方式 如get参数
         */
        echo '开始握手'.PHP_EOL;
        $headers = $request->header;
        $cookie = $request->cookie;

        // if (如果不满足我某些自定义的需求条件，返回false，握手失败) {
        //    return false;
        // }
        return true;
    }

    /**
     * RFC规范中的WebSocket握手验证过程
     * 以下内容必须强制使用
     *
     * @param \swoole_http_request  $request
     * @param \swoole_http_response $response
     * @return bool
     */
    protected function secWebsocketAccept(\swoole_http_request $request, \swoole_http_response $response): bool
    {

        // ws rfc 规范中约定的验证过程
        if (!isset($request->header['sec-websocket-key'])) {
            // 需要 Sec-WebSocket-Key 如果没有拒绝握手
            var_dump('shake fai1 3');
            return false;
        }

        if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
            || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
        ) {
            //不接受握手
            var_dump('shake fai1 4');
            return false;
        }

        $key = base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
        $headers = array(
            'Upgrade'               => 'websocket',
            'Connection'            => 'Upgrade',
            'Sec-WebSocket-Accept'  => $key,
            'Sec-WebSocket-Version' => '13',
            'KeepAlive'             => 'off',
        );

        if (isset($request->header['sec-websocket-protocol'])) {
            $headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol'];
        }

        // 发送验证后的header
        foreach ($headers as $key => $val) {
            $response->header($key, $val);
        }

        // 接受握手 还需要101状态码以切换状态


        if(!isset($request->header['access_key'])){
           # $response->status(400);
            #return false;
            $request->header['access_key'] = 'asdawsfesadfgews';
        }
        $appLogic = new AppLogic();
        $app = $appLogic->findByAccessKey($request->header['access_key']);
        if(!is_object( $app )){
            $response->status(400);
            return false;
        }
        $response->status(101);
        #这个位置后续增加
        $fdToAppTable = TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.fd_to_app'));
        $fdToAppTable->set($request->fd,['access_key'=>$app['access_key'],'secret_key'=>$app['secret_key']]);
        //验证token是否合法
    /*    try {
            $jwtObject = Jwt::getInstance()->decode($getData['token']);
            $status =  $jwtObject->getStatus();
            if($status!=1&&$status!=-2){
                echo 'token失效'.PHP_EOL;
                return false;
            }
            $userInfo =  $jwtObject->getData();

            $onlineData['nickname'] = $userInfo['nickname'];
            $onlineData['fd'] = $request->fd;
            $onlineData['server'] = Config::getInstance()->getConf('APP.CURRENT.host');
            $onlineData['head'] = $userInfo['head'];
            $onlineData['user_id'] = $userInfo['id'];
            $onlineData['app_id'] = $userInfo['app_id'];

            $table = TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.online_user'));

            //全部在线用户集合
            $table->set($userInfo['id'], $onlineData);
            //绑定用户id
            echo $userInfo['id'].'连接到服务器了'. $request->fd.PHP_EOL;
            #绑定fd-uid
            $server = ServerManager::getInstance()->getSwooleServer();
            $server->bind($request->fd,$userInfo['id']);
            #通知中间服务器
            $masterService = new MasterService();
            $masterService->online($onlineData);
            #添加消息同步任务
            $syncTable = TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.sync_message'));
            $syncTable->set($userInfo['id'],['fd'=>$request->fd,'user_id'=>$userInfo['id']]);
        } catch (\EasySwoole\Jwt\Exception $e) {
            #没有绑定的用户，自动踢掉
        }*/

        return true;
    }

    /**
     * 关闭事件
     *
     * @param \swoole_server $server
     * @param int            $fd
     * @param int            $reactorId
     */
    public function onClose(\swoole_server $server, int $fd, int $reactorId)
    {
        /** @var array $info */
        $info = $server->getClientInfo($fd);
        /**
         * 判断此fd 是否是一个有效的 websocket 连接
         * 参见 https://wiki.swoole.com/wiki/page/490.html
         */
        if ($info && $info['websocket_status'] === WEBSOCKET_STATUS_FRAME) {
            /**
             * 判断连接是否是 server 主动关闭
             * 参见 https://wiki.swoole.com/wiki/page/p-event/onClose.html
             */
            if ($reactorId < 0) {
                echo "server close \n";

            }
        }
        //删除关联
        $table = TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.online_user'));
        if(isset($info['uid'])){
            $userInfo =  $table->get($info['uid']);
            if(!empty( $userInfo)&& $userInfo['fd']==$fd){
                $table->del($info['uid']);
                #通知中间服务器断开连接信息
                $masterService = new MasterService();
                $offlineData['server'] = $userInfo['server'];
                $offlineData['user_id'] = $info['uid'];
                $offlineData['fd'] = $fd;
                $masterService->offline( $offlineData);
                #记录下线时间
                $redisPool = \EasySwoole\RedisPool\Redis::getInstance()->get('redis');
                $redis = $redisPool->getObj();
                $redis->hSet(Config::getInstance()->getConf('CHAT.user_offline_time'),$info['uid'],HelpService::msectime());
                $redisPool->recycleObj($redis);
               #删除就绪信息
                $readyTable =  TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.user_ready'));
                $readyTable->del($info['uid']);
                #删除在线信息
                $onlineTable =  TableManager::getInstance()->get(Config::getInstance()->getConf('CHAT.online_user'));
                $onlineTable->del($info['uid']);
            }
        }


    }

}